package cranim.crparsing;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author Benedikt
 */
public class CRParser {

    private CRParse result;
    private Pattern pattern;
    private Matcher matcher;
    
    private String text;
    private String formattedText;
    private String lang;    

    String intro, vs, attacker, defender, weapons, shields, hull, type, count, arms, totalstrength, attackshoots, attackshield, defshoots, defshield, defeated, won, total, units, df, now, metal, crystal, loots, and;
    String scargo, lcargo, lfighter, hfighter, cruiser, bship, colship, recycler, probe, solsat, solsat2, bomber, solsatrplc, destroyer, deathstar, bcrusier;
    String rlauncher, llaser, hlaser, gauss, ioncan, plasmatur, sshield, lshield;
     
    
    public CRParser() {
    }
    
    public void setText(String cr){
        text = cr;
    }
    
    public CRParse getResult(){
        
        return result;
    }
    
    public void parse(){

        result = new CRParse();
        String res = "";
        
        ParsePlayer attPlayer = new ParsePlayer();
        ParsePlayer defPlayer = new ParsePlayer();
        List<ParseFleet> attFleets = new ArrayList<>();
        List<ParseFleet> defFleets = new ArrayList<>();
        
        String dfDe = "Auf diesen Raumkoordinaten liegen nun";
        
        String langDePattern = ".*"+dfDe+".*";
        pattern = Pattern.compile(langDePattern, java.util.regex.Pattern.DOTALL+java.util.regex.Pattern.CANON_EQ+java.util.regex.Pattern.CASE_INSENSITIVE);
        matcher = pattern.matcher(text);
        
        if (matcher.matches()) lang = "DE";
   
        if(lang.equals("DE")){
            intro = "Folgende Flotten stehen sich";            
            vs = "vs.";
            attacker = "Angreifer";
            defender = "Verteidiger";            
            weapons = "Waffen";
            shields = "Schilde";
            hull = "Hülle";
            type = "Typ";
            count = "Anz.";
            arms = "Bewaff.";
            attackshoots = "Die angreifende Flotte schießt insgesamt" ;
            totalstrength = "Gesamtstärke";
            defshield = "Die Schilde des Verteidigers absorbieren";
            defshoots = "Die verteidigende Flotte schießt insgesamt"; 
            attackshield = "Die Schilde des Angreifers absorbieren";    
            defeated  = "vernichtet";
            won = "hat die Schlacht gewonnen.";
            total = "insgesamt";
            units = "Units";        
            df = "Auf diesen Raumkoordinaten liegen nun";
            now = "nun";
            and = "und";
            metal = "Metall";
            crystal = "Kristall";
            loots = "erbeutet";    
            scargo = "Kl.Trans";
            lcargo = "Gr.Trans";
            lfighter = "L.Jäger";
            hfighter = "S.Jäger";
            cruiser = "Kreuzer";
            bship = "Schlachts.";
            colship = "Kol.";
            recycler = "Recy.";
            probe = "Spio.Sonde";        
            solsat =  "Sol.Sat";  
            solsat2 =  "S.Satellit";  
            bomber = "Bomber";
            solsatrplc =  "Sol. Sat";
            destroyer = "Zerst.";
            deathstar = "Rip";
            bcrusier = "Schlachtkr.";
            rlauncher = "Rak.";
            llaser = "L.Laser";
            hlaser = "S.Laser";
            gauss = "Gauß";
            ioncan = "Ion.W";
            plasmatur = "Plasma";
            sshield = "S.Kuppel";
            lshield = "GS.Kuppel";
            
            formattedText = text.replaceAll(solsatrplc, solsat);
        }
            
        if(lang.equals("EN")){     
            
        }
        
        String roundStrings[] = formattedText.split(attackshoots);
        int numRounds = roundStrings.length;
        
        //Get date and time if available
        String timePattern = ".*\\((31|30|[012]\\d|\\d)[./](0\\d|1[012]|\\d)[./](\\d{4}|\\d\\d)\\s([01]?\\d|2[0-3]):([0-5]?\\d):([0-5]?\\d).*";
        pattern = Pattern.compile(timePattern, java.util.regex.Pattern.DOTALL+java.util.regex.Pattern.CANON_EQ);
        matcher = pattern.matcher(roundStrings[0]);
        if (matcher.matches()){
            matcher.groupCount();
            String day = matcher.group(1);
            String month = matcher.group(2);
            String year = matcher.group(3);
            String hour = matcher.group(4);
            String minute = matcher.group(5);
            String second = matcher.group(6);
            result.setTime(day+"."+month+"."+year+" "+hour+":"+minute+":"+second);
            
            res += day+"."+month+"."+year+"\n";
        }
        else{
            res += "Unknown Date\n";
        }
        //Get player names if available
        String namesPattern = ".*\\s(\\S+)\\s"+vs+"\\s(\\S+)\\s.*";
        pattern = Pattern.compile(namesPattern, java.util.regex.Pattern.DOTALL+java.util.regex.Pattern.CANON_EQ);
        matcher = pattern.matcher(roundStrings[0]);
        if (matcher.matches()){
            matcher.groupCount();
            String attackerName = matcher.group(1);
            String defenderName = matcher.group(2);
            attPlayer.setName(attackerName);
            defPlayer.setName(defenderName);
            
            res += attackerName+" vs. "+defenderName+"\n";
        }
        else{
            res += "Unknown Names\n";
        }
        //Get coords if available
        String coordsPattern = ".*(\\[\\d+:\\d+:\\d+\\]).*(\\[\\d+:\\d+:\\d+\\]).*";
        pattern = Pattern.compile(coordsPattern, java.util.regex.Pattern.DOTALL+java.util.regex.Pattern.CANON_EQ);
        matcher = pattern.matcher(roundStrings[0]);
        if (matcher.matches()){
            matcher.groupCount();
            String attackerCoords = matcher.group(1);
            String defenderCoords = matcher.group(2);
            attPlayer.setCoords(attackerCoords);
            defPlayer.setCoords(defenderCoords);
            
            res += attackerCoords+" vs. "+defenderCoords+"\n";
        }
        else{
            res += "Unknown Coords\n";
        }
        //Attacker tech levels
        String attlevelPattern = ".*"+attacker+".*"+weapons+"\\D*(\\d+)%.*\\D(\\d+)%.*\\D(\\d+)%.*"+defender+".*";

        pattern = Pattern.compile(attlevelPattern, java.util.regex.Pattern.DOTALL+java.util.regex.Pattern.CANON_EQ);
        matcher = pattern.matcher(roundStrings[0]);

        if (matcher.matches()){
            matcher.groupCount();
            String attackerWeapons = matcher.group(1);
            String attackerShields = matcher.group(2);
            String attackerHull = matcher.group(3);            
            int[] atttechs = {Integer.valueOf(attackerWeapons)/10,Integer.valueOf(attackerShields)/10,Integer.valueOf(attackerHull)/10};
            attPlayer.setTechs(atttechs);
             
            res += "Attacker Weapons "+attackerWeapons;
            res += " Attacker Shields "+attackerShields;
            res += " Attacker Hull "+attackerHull;
            res += "\n";
        }
        else{
            res += "No attacker tech levels found\n";

        }
        //Defender tech levels
        String deflevelPattern = ".*"+defender+".*"+weapons+"\\D*(\\d+)%.*\\D(\\d+)%.*\\D(\\d+)%.*";

        pattern = Pattern.compile(deflevelPattern, java.util.regex.Pattern.DOTALL+java.util.regex.Pattern.CANON_EQ);
        matcher = pattern.matcher(roundStrings[0]);

        if (matcher.matches()){
            matcher.groupCount();
            String defenderWeapons = matcher.group(1);
            String defenderShields = matcher.group(2);
            String defenderHull = matcher.group(3);            
            int[] deftechs = {Integer.valueOf(defenderWeapons)/10,Integer.valueOf(defenderShields)/10,Integer.valueOf(defenderHull)/10};            
            defPlayer.setTechs(deftechs);

            res += "Defender Weapons "+defenderWeapons;
            res += " Defender Shields "+defenderShields;
            res += " Defender Hull "+defenderHull;

            res += "\n";
        }
        else{
            res += "No defender tech levels found\n";
        }
        
        for(int i = 0; i < numRounds; i++){
            res += "Round "+i+"\n";
            
            
            ParseFleet attFleet = new ParseFleet();
            ParseFleet defFleet = new ParseFleet();
            List<String> attFleetShipNamesArray = new ArrayList<>();
            List<Integer> attFleetShipCountArray = new ArrayList<>();
            List<String> defFleetShipNamesArray = new ArrayList<>();
            List<Integer> defFleetShipCountArray = new ArrayList<>();
            
            //Attacker fleet
            String attshipnamesPattern = ".*"+attacker+"(?:(?!"+defeated+").)*"+type+"\\s+((?:(?:\\S+)\\s+)+)"+count;
            String attshipcountPattern = "\\s+((?:(?:\\S+)\\s+)+).*"+arms+".*"+defender+".*";
            String attfleetPattern = attshipnamesPattern+attshipcountPattern;

            pattern = Pattern.compile(attfleetPattern, java.util.regex.Pattern.DOTALL+java.util.regex.Pattern.CANON_EQ);
            matcher = pattern.matcher(roundStrings[i]);

            if (matcher.matches()){
                String attackerShipnames = matcher.group(1);
                String attackerShipcounts = matcher.group(2);
                
                String namesandnumbers = "(\\S+)";
                pattern = Pattern.compile(namesandnumbers, java.util.regex.Pattern.DOTALL+java.util.regex.Pattern.CANON_EQ);
                matcher = pattern.matcher(attackerShipnames);
                int differentunits = 0;
                while(matcher.find()){
                    attFleetShipNamesArray.add(matcher.group());
                    differentunits++;
                }                
                matcher = pattern.matcher(attackerShipcounts);
                differentunits = 0;
                while(matcher.find()){
                    formattedText = matcher.group().replaceAll("\\.", "");
                    attFleetShipCountArray.add(Integer.valueOf(formattedText));
                    differentunits++;
                }
                for(int attunits = 0; attunits < differentunits; attunits++){
                    res += "Attacker ships "+Integer.valueOf(attFleetShipCountArray.get(attunits))+" "+attFleetShipNamesArray.get(attunits);                
                    res += "\n";
                }
            }
            else{
                String attdefeatedPattern = ".*"+attacker+"\\s+\\S+\\s+"+defeated+".*";
                pattern = Pattern.compile(attdefeatedPattern, java.util.regex.Pattern.DOTALL+java.util.regex.Pattern.CANON_EQ);
                matcher = pattern.matcher(roundStrings[i]);
                if(matcher.matches()){
                    res += "Attacker defeated\n";
                    
                }
                else{
                    System.out.println("Crital Error");
                    System.out.println("Attacker parser round " + i);
                }
            }
            
            if(attFleetShipCountArray.size() == attFleetShipNamesArray.size()){
                for(int attunits = 0; attunits < attFleetShipNamesArray.size(); attunits++){
                    if(attFleetShipNamesArray.get(attunits).equals(scargo))
                            attFleet.scargo = attFleetShipCountArray.get(attunits);
                    else if(attFleetShipNamesArray.get(attunits).equals(lcargo))
                            attFleet.lcargo = attFleetShipCountArray.get(attunits);
                    else if(attFleetShipNamesArray.get(attunits).equals(lfighter))
                            attFleet.lfighter = attFleetShipCountArray.get(attunits);
                    else if(attFleetShipNamesArray.get(attunits).equals(hfighter))
                            attFleet.hfighter = attFleetShipCountArray.get(attunits);
                    else if(attFleetShipNamesArray.get(attunits).equals(cruiser))
                            attFleet.cruiser = attFleetShipCountArray.get(attunits);
                    else if(attFleetShipNamesArray.get(attunits).equals(bship))
                            attFleet.bship = attFleetShipCountArray.get(attunits);
                    else if(attFleetShipNamesArray.get(attunits).equals(colship))
                            attFleet.colship = attFleetShipCountArray.get(attunits);
                    else if(attFleetShipNamesArray.get(attunits).equals(recycler))     
                            attFleet.recycler = attFleetShipCountArray.get(attunits);
                    else if(attFleetShipNamesArray.get(attunits).equals(probe))
                            attFleet.probe = attFleetShipCountArray.get(attunits);
                    else if(attFleetShipNamesArray.get(attunits).equals(bomber))
                            attFleet.bomber = attFleetShipCountArray.get(attunits);
                    else if(attFleetShipNamesArray.get(attunits).equals(destroyer))
                            attFleet.destroyer = attFleetShipCountArray.get(attunits);
                    else if(attFleetShipNamesArray.get(attunits).equals(deathstar))
                            attFleet.deathstar = attFleetShipCountArray.get(attunits);
                    else if(attFleetShipNamesArray.get(attunits).equals(bcrusier))
                            attFleet.bcruiser = attFleetShipCountArray.get(attunits);
                    else{
                        System.out.println("Crital Error");
                        System.out.println("Unknown attacker ship " + attFleetShipNamesArray.get(attunits));
                    }
                }
            }
            else{
                System.out.println("Crital Error");
                System.out.println("Atacker array sizes don't match");
            }

            //Defender fleet
            String defshipnamesPattern = ".*"+defender+"(?:(?!"+defeated+").)*"+type+"\\s+((?:(?:\\S+)\\s+)+)"+count;
            String defshipcountPattern = "\\s+((?:(?:\\S+)\\s+)+)"+arms+".*";
            String deffleetPattern = defshipnamesPattern+defshipcountPattern;

            pattern = Pattern.compile(deffleetPattern, java.util.regex.Pattern.DOTALL+java.util.regex.Pattern.CANON_EQ);
            matcher = pattern.matcher(roundStrings[i]);

            if (matcher.matches()){
                String defenderShipnames = matcher.group(1);
                String defenderShipcounts = matcher.group(2);
                
                String namesandnumbers = "(\\S+)";
                pattern = Pattern.compile(namesandnumbers, java.util.regex.Pattern.DOTALL+java.util.regex.Pattern.CANON_EQ);
                matcher = pattern.matcher(defenderShipnames);
                int differentunits = 0;
                while(matcher.find()){
                    defFleetShipNamesArray.add(matcher.group());
                    differentunits++;
                }                
                matcher = pattern.matcher(defenderShipcounts);
                differentunits = 0;
                while(matcher.find()){
                    formattedText = matcher.group().replaceAll("\\.", "");
                    defFleetShipCountArray.add(Integer.valueOf(formattedText));
                    differentunits++;
                }
                for(int defunits = 0; defunits < differentunits; defunits++){
                    res += "Defender ships "+Integer.valueOf(defFleetShipCountArray.get(defunits))+" "+defFleetShipNamesArray.get(defunits);                
                    res += "\n";
                }
            }
            else{
                String defdefeatedPattern = ".*"+defender+"\\s+\\S+\\s+"+defeated+".*";
                pattern = Pattern.compile(defdefeatedPattern, java.util.regex.Pattern.DOTALL+java.util.regex.Pattern.CANON_EQ);
                matcher = pattern.matcher(roundStrings[i]);
                if(matcher.matches()){
                    res += "Defender defeated\n";
                    
                }
                else{
                    System.out.println("Crital Error");
                    System.out.println("Defender parser round " + i);
                }
            }
            
            if(defFleetShipCountArray.size() == defFleetShipNamesArray.size()){
                for(int defunits = 0; defunits < defFleetShipNamesArray.size(); defunits++){
                    if(defFleetShipNamesArray.get(defunits).equals(scargo))
                            defFleet.scargo = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(lcargo))
                            defFleet.lcargo = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(lfighter))
                            defFleet.lfighter = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(hfighter))
                            defFleet.hfighter = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(cruiser))
                            defFleet.cruiser = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(bship))
                            defFleet.bship = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(colship))
                            defFleet.colship = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(recycler))     
                            defFleet.recycler = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(probe))
                            defFleet.probe = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(solsat) || defFleetShipNamesArray.get(defunits).equals(solsat2))
                            defFleet.solsat = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(bomber))
                            defFleet.bomber = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(destroyer))
                            defFleet.destroyer = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(deathstar))
                            defFleet.deathstar = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(bcrusier))
                            defFleet.bcruiser = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(rlauncher))
                            defFleet.rlauncher = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(llaser))
                            defFleet.llaser = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(hlaser))
                            defFleet.hlaser = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(gauss))
                            defFleet.gauss = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(ioncan))
                            defFleet.ioncan = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(plasmatur))
                            defFleet.plasmatur = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(sshield))
                            defFleet.sshield = defFleetShipCountArray.get(defunits);
                    else if(defFleetShipNamesArray.get(defunits).equals(lshield))
                            defFleet.lshield = defFleetShipCountArray.get(defunits);
                    else{
                        System.out.println("Crital Error");
                        System.out.println("Unknown defender ship " + defFleetShipNamesArray.get(defunits));
                    }
                }
            }
            else{
                System.out.println("Crital Error");
                System.out.println("Defender array sizes don't match");
            }
            attFleets.add(i, attFleet);
            defFleets.add(i, defFleet);
        }
        
        //Loot
        String lootPattern = ".*"+loots+"\\s+(\\S+)\\s+"+metal+",\\s+(\\S+)\\s+"+crystal+"\\s+und\\s+(\\S+)\\s+.*";
        pattern = Pattern.compile(lootPattern, java.util.regex.Pattern.DOTALL+java.util.regex.Pattern.CANON_EQ);
        matcher = pattern.matcher(roundStrings[numRounds-1]);
        if(matcher.matches()){
            String lootmetS = matcher.group(1);   
            String lootkrisS = matcher.group(2);    
            String lootdeutS = matcher.group(2);  
            
            BigInteger lootmet = new BigInteger(lootmetS.replaceAll("[,\\.]", ""));
            BigInteger lootkris = new BigInteger(lootkrisS.replaceAll("[,\\.]", ""));
            BigInteger lootdeut = new BigInteger(lootdeutS.replaceAll("[,\\.]", ""));
            result.setLoot(lootmet, lootkris, lootdeut);
            
            res += "Attacker loots "+lootmetS+" metal "+lootkrisS+" crystal "+lootdeut+" deuterium\n";

        }
        else{
            res += "No loot :(\n";
        }
        
        //Units
        String conclusionPattern = ".*"+total+"\\s+(\\S+)\\s+"+units+".*"+total+"\\s+(\\S+)\\s+"+units+".*"+now+"\\s+(\\S+)\\s+"+metal+"\\s+"+and+"\\s+(\\S+)\\s+.*";
        pattern = Pattern.compile(conclusionPattern, java.util.regex.Pattern.DOTALL+java.util.regex.Pattern.CANON_EQ);
        matcher = pattern.matcher(roundStrings[numRounds-1]);
        if(matcher.matches()){
            String attlostS = matcher.group(1);
            String deflostS = matcher.group(2);
            String dfmetalS = matcher.group(3);   
            String dfkrisS = matcher.group(4);   
            
            BigInteger attlost = new BigInteger(attlostS.replaceAll("[,\\.]", ""));
            BigInteger deflost = new BigInteger(deflostS.replaceAll("[,\\.]", ""));
            BigInteger dfmetal = new BigInteger(dfmetalS.replaceAll("[,\\.]", ""));
            BigInteger dfkris = new BigInteger(dfkrisS.replaceAll("[,\\.]", ""));
            result.setMSE(attlost, deflost, dfmetal, dfkris);
            
            res += "Attacker lost Units "+attlostS+"\n";
            res += "Defender lost Units "+deflostS+"\n";
            res += "Debris field "+dfmetalS+" metal "+dfkrisS+" crystal\n";

        }
        else{
            System.out.println("Crital Error");
            System.out.println("No lost units summary");
        }        
        //TODO Restored def

        
        attPlayer.setFleets(attFleets);
        defPlayer.setFleets(defFleets);
        result.setAttacker(attPlayer);
        result.setDefender(defPlayer);
        result.setTemp(res);
    }
}
